#ifndef CDAMAGEEVENT_H
#define CDAMAGEEVENT_H

#include "CDamageType.h"
/** Event used by AActor::TakeDamage and related functions */
struct CDamageEvent
{
public:
	/** Default constructor (no initialization). */
	CDamageEvent() {}
	CDamageEvent(CDamageEvent const& InDamageEvent)
		: DamageTypeClass(InDamageEvent.DamageTypeClass)
	{ }
	virtual ~CDamageEvent() { }

	explicit CDamageEvent(CDamageType InDamageTypeClass)
		: DamageTypeClass(InDamageTypeClass)
	{ }

	/** Optional DamageType for this event.  If nullptr, UDamageType will be assumed. */
	CDamageType DamageTypeClass;

	/** ID for this class. NOTE this must be unique for all damage events. */
	static const unsigned int ClassID = 0;

	virtual unsigned int GetTypeID() const { return CDamageEvent::ClassID; }
	virtual bool IsOfType(unsigned int InID) const { return CDamageEvent::ClassID == InID; };

	/** This is for compatibility with old-style functions which want a unified set of hit data regardless of type of hit.  Ideally this will go away over time. */
	//virtual void GetBestHitInfo(AActor const* HitActor, AActor const* HitInstigator, struct FHitResult& OutHitInfo, FVector& OutImpulseDir) const;
};

/** Damage subclass that handles damage with a single impact location and source direction */
struct FPointDamageEvent : public CDamageEvent
{
		/** Actual damage done */
		float Damage;

	/** Direction the shot came from. Should be normalized. */
		int ShotDirection;

	/** Describes the trace/location that caused this damage */
		//struct FHitResult HitInfo;

	FPointDamageEvent() : Damage(0.0f), ShotDirection(0x00) {}
	FPointDamageEvent(float InDamage, int InShotDirection, CDamageType &InDamageTypeClass)
		: CDamageEvent(InDamageTypeClass), Damage(InDamage), ShotDirection(InShotDirection)
	{}

	/** ID for this class. NOTE this must be unique for all damage events. */
	static const unsigned int ClassID = 1;

	virtual unsigned int GetTypeID() const override { return FPointDamageEvent::ClassID; };
	virtual bool IsOfType(unsigned int InID) const override { return (FPointDamageEvent::ClassID == InID) || CDamageEvent::IsOfType(InID); };

	/** Simple API for common cases where we are happy to assume a single hit is expected, even though damage event may have multiple hits. */
	//virtual void GetBestHitInfo(AActor const* HitActor, AActor const* HitInstigator, struct FHitResult& OutHitInfo, FVector& OutImpulseDir) const override;
};

/** Parameters used to compute radial damage */
struct FRadialDamageParams
{
		/** Max damage done */
		//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = RadialDamageParams)
		float BaseDamage;

	/** Damage will not fall below this if within range */
	//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = RadialDamageParams)
		float MinimumDamage;

	/** Within InnerRadius, do max damage */
	//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = RadialDamageParams)
		float InnerRadius;

	/** Outside OuterRadius, do no damage */
	//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = RadialDamageParams)
		float OuterRadius;

	/** Describes amount of exponential damage falloff */
	//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = RadialDamageParams)
		float DamageFalloff;

	FRadialDamageParams()
		: BaseDamage(0.f), MinimumDamage(0.f), InnerRadius(0.f), OuterRadius(0.f), DamageFalloff(1.f)
	{}
	FRadialDamageParams(float InBaseDamage, float InInnerRadius, float InOuterRadius, float InDamageFalloff)
		: BaseDamage(InBaseDamage), MinimumDamage(0.f), InnerRadius(InInnerRadius), OuterRadius(InOuterRadius), DamageFalloff(InDamageFalloff)
	{}
	FRadialDamageParams(float InBaseDamage, float InMinimumDamage, float InInnerRadius, float InOuterRadius, float InDamageFalloff)
		: BaseDamage(InBaseDamage), MinimumDamage(InMinimumDamage), InnerRadius(InInnerRadius), OuterRadius(InOuterRadius), DamageFalloff(InDamageFalloff)
	{}
	FRadialDamageParams(float InBaseDamage, float InRadius)
		: BaseDamage(InBaseDamage), MinimumDamage(0.f), InnerRadius(0.f), OuterRadius(InRadius), DamageFalloff(1.f)
	{}

	/** Returns damage done at a certain distance */
	

	/** Return outermost radius of the damage area. Protects against malformed data. */
	
};

/** Damage subclass that handles damage with a source location and falloff radius */
struct FRadialDamageEvent : public CDamageEvent
{
		/** Static parameters describing damage falloff math */
		FRadialDamageParams Params;

	/** Location of origin point */
		//FVector Origin;

	/** Hit reslts of specific impacts */
		//TArray<struct FHitResult> ComponentHits;

	/** ID for this class. NOTE this must be unique for all damage events. */
	static const unsigned int ClassID = 2;

	virtual unsigned int GetTypeID() const override { return FRadialDamageEvent::ClassID; };
	virtual bool IsOfType(unsigned int InID) const override { return (FRadialDamageEvent::ClassID == InID) || CDamageEvent::IsOfType(InID); };

	/** Simple API for common cases where we are happy to assume a single hit is expected, even though damage event may have multiple hits. */
	//virtual void GetBestHitInfo(AActor const* HitActor, AActor const* HitInstigator, struct FHitResult& OutHitInfo, FVector& OutImpulseDir) const override;

	FRadialDamageEvent(){}
	~FRadialDamageEvent(){}
};

#endif